package my.edu.aspect;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import my.edu.model.information.entity.OperationLog;
import my.edu.model.information.service.IOperationLogService;
import my.edu.security.userEntity.UserDetail;
import my.edu.utils.ThreadLocalUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.Arrays;

@Aspect
@Component
@Slf4j
public class OperateAspect {

    @Autowired
    private IOperationLogService operationLogService;


    @Pointcut("execution(* my.edu.model..*.controller.*.*(..)) ")
    //第一个*：返回值类型；后面就是 my.edu.model 包及其所有子包中的 controller 子包下的所有方法，包括所有参数类型
    public void autoFillPointCut() {
    }

    @Before("autoFillPointCut()")
    public void logMethodParameters(JoinPoint joinPoint) {
        OperationLog operationLog = ThreadLocalUtil.getOperationLog();
        // 获取用户 IP 地址
        operationLog.setIp(getUserIp());
        //获取时间
        operationLog.setTime(LocalDateTime.now());
        //获取模块名
        String name = joinPoint.getTarget().getClass().getName();
        String[] parts = name.split("\\.");
        String result = String.join(".", Arrays.copyOfRange(parts, 2, parts.length));
        operationLog.setOperationModule(result);
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        operationLog.setOperationMethod(methodName);
        // 获取参数
        Object[] args = joinPoint.getArgs();
        // 将参数转化为 JSON 字符串
        String argsJson = JSONUtil.toJsonStr(args);
        // 记录方法名和参数
        log.info("Method: {} is called with arguments: {}", methodName, args);
        operationLog.setOperationData(argsJson);
    }

    @AfterReturning(pointcut = "autoFillPointCut()", returning = "result")
    public void logMethodReturn(JoinPoint joinPoint, Object result) {
        OperationLog operationLog = ThreadLocalUtil.getOperationLog();
        operationLog.setStatus(1);
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        Signature signature = joinPoint.getSignature();
        // 记录方法返回值
        log.info("Method: {} returned with result: {}", methodName, result);
        String jsonStr = JSONUtil.toJsonStr(result);
        operationLog.setOperationResult(jsonStr);
        setLog(operationLog);
    }

    @AfterThrowing(pointcut = "autoFillPointCut()", throwing = "ex")
    public void logMethodException(JoinPoint joinPoint, Throwable ex) {
        OperationLog operationLog = ThreadLocalUtil.getOperationLog();
        operationLog.setStatus(0);
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        // 记录异常信息
        log.error("Method: {} threw an exception: {}", methodName, ex.getMessage(), ex);
        operationLog.setOperationResult(ex.getMessage());
        setLog(operationLog);
    }

    private void setLog(OperationLog operationLog) {
        Long userId;
        //获取id
        Object principal = SecurityUtils.getSubject().getPrincipal();
        if (principal != null) {
            userId = ((UserDetail) principal).getId();
        } else {
           userId = ThreadLocalUtil.getCurrentId();
            ThreadLocalUtil.removeCurrentId();
          //  userId = (Long) SecurityUtils.getSubject().getSession().getAttribute("userId");
        }
        operationLog.setUserId(userId);

        // 检查并截断 operation_result 字段
        String operationResult = operationLog.getOperationResult();
        int maxLength = 4000; // 根据实际情况调整最大长度
        if (operationResult != null && operationResult.length() > maxLength) {
            operationLog.setOperationResult(operationResult.substring(0, maxLength));
            log.warn("operation_result 被截断，原始长度为: {}", operationResult.length());
        }

        operationLogService.save(operationLog);
        ThreadLocalUtil.removeOperationLog();
    }

    private String getUserIp() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            return getClientIp(request);
        }
        return null;
    }

    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // X-Forwarded-For 可能包含多个 IP 地址，取第一个非 unknown 的
            String[] ips = ip.split(",");
            for (String candidate : ips) {
                if (!"unknown".equalsIgnoreCase(candidate.trim())) {
                    return candidate.trim();
                }
            }
        }

        ip = request.getHeader("Proxy-Client-IP");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_CLIENT_IP");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        // 如果以上都没有，则使用 request.getRemoteAddr()
        return request.getRemoteAddr();
    }
}
